/**
 * Example 4: Unified Event Creation Mode
 *
 * This example demonstrates a solution to the mixed reset mode problem using
 * a centralized event service that ensures all modules use a consistent
 * event creation pattern.
 */

#include <Windows.h>
#include <iostream>
#include <string>
#include <vector>
#include <mutex>

// EventService class for unified event creation and management
class EventService {
private:
    // Singleton pattern
    static EventService* s_instance;
    static std::mutex s_mutex;
    
    // Store created events
    struct EventInfo {
        HANDLE handle;
        bool isManualReset;
        bool initialState;
    };
    
    std::map<std::wstring, EventInfo> m_events;
    
public:
    // Get the singleton instance
    static EventService* GetInstance() {
        std::lock_guard<std::mutex> lock(s_mutex);
        if (s_instance == nullptr) {
            s_instance = new EventService();
        }
        return s_instance;
    }
    
    // Get an event handle, creating it if necessary
    HANDLE GetEvent(const std::wstring& name, bool manualReset, bool initialState) {
        std::lock_guard<std::mutex> lock(s_mutex);
        
        // Check if we already have this event
        auto it = m_events.find(name);
        if (it != m_events.end()) {
            // Event exists, verify the parameters match
            if (it->second.isManualReset != manualReset) {
                std::cout << "WARNING: Requested reset mode (" 
                          << (manualReset ? "manual" : "auto") 
                          << ") doesn't match existing event's mode (" 
                          << (it->second.isManualReset ? "manual" : "auto") 
                          << ") for event '" << name.c_str() << "'" << std::endl;
            }
            return it->second.handle;
        }
        
        // Create a new event
        std::cout << "EventService: Creating " << (manualReset ? "manual" : "auto") 
                  << "-reset event '" << name.c_str() << "'" << std::endl;
        
        HANDLE hEvent = CreateEvent(
            NULL,           // Default security attributes
            manualReset,    // Reset mode as requested
            initialState,   // Initial state as requested
            name.c_str()    // Event name
        );
        
        if (hEvent == NULL) {
            std::cerr << "CreateEvent failed with error " << GetLastError() << std::endl;
            return NULL;
        }
        
        // Store the new event
        EventInfo info = { hEvent, manualReset, initialState };
        m_events[name] = info;
        
        return hEvent;
    }
    
    // Clean up all events
    ~EventService() {
        for (auto& pair : m_events) {
            CloseHandle(pair.second.handle);
        }
        m_events.clear();
    }
};

// Initialize static members
EventService* EventService::s_instance = nullptr;
std::mutex EventService::s_mutex;

// Simulate different modules using the EventService

// Module A
class ModuleA {
public:
    static HANDLE GetSystemStatusEvent() {
        // Always uses the EventService
        return EventService::GetInstance()->GetEvent(
            L"Global\\Example4_SystemStatus",
            true,   // Manual reset
            false   // Initially not signaled
        );
    }
    
    static DWORD WINAPI ThreadFunc(LPVOID lpParam) {
        HANDLE hEvent = GetSystemStatusEvent();
        std::cout << "Module A: Waiting for event signal..." << std::endl;
        
        DWORD waitResult = WaitForSingleObject(hEvent, INFINITE);
        
        if (waitResult == WAIT_OBJECT_0) {
            std::cout << "Module A: Event signaled! Processing..." << std::endl;
            Sleep(500);  // Simulate processing
            
            // Module A knows it's a manual reset event, so it resets it
            std::cout << "Module A: Resetting the manual-reset event" << std::endl;
            ResetEvent(hEvent);
            
            std::cout << "Module A: Processing complete" << std::endl;
        }
        
        return 0;
    }
};

// Module B
class ModuleB {
public:
    static HANDLE GetSystemStatusEvent() {
        // Uses the EventService but requests auto-reset mode
        // EventService will return the existing handle with a warning
        return EventService::GetInstance()->GetEvent(
            L"Global\\Example4_SystemStatus",
            false,  // Auto reset (this will be ignored/warned if event exists)
            false   // Initially not signaled
        );
    }
    
    static DWORD WINAPI ThreadFunc(LPVOID lpParam) {
        HANDLE hEvent = GetSystemStatusEvent();
        std::cout << "Module B: Waiting for event signal..." << std::endl;
        
        DWORD waitResult = WaitForSingleObject(hEvent, INFINITE);
        
        if (waitResult == WAIT_OBJECT_0) {
            std::cout << "Module B: Event signaled! Processing..." << std::endl;
            Sleep(500);  // Simulate processing
            
            // Module B thinks it's an auto-reset event, but follows best practice
            // and calls ResetEvent anyway (which is safe even if redundant)
            std::cout << "Module B: Following best practice, explicitly resetting the event" << std::endl;
            ResetEvent(hEvent);
            
            std::cout << "Module B: Processing complete" << std::endl;
        }
        
        return 0;
    }
};

// Module C
class ModuleC {
public:
    static HANDLE GetSystemStatusEvent() {
        // Also uses the EventService with the same parameters as Module A
        return EventService::GetInstance()->GetEvent(
            L"Global\\Example4_SystemStatus",
            true,   // Manual reset (consistent with first creation)
            false   // Initially not signaled
        );
    }
    
    static DWORD WINAPI ThreadFunc(LPVOID lpParam) {
        HANDLE hEvent = GetSystemStatusEvent();
        std::cout << "Module C: Waiting for event signal..." << std::endl;
        
        DWORD waitResult = WaitForSingleObject(hEvent, INFINITE);
        
        if (waitResult == WAIT_OBJECT_0) {
            std::cout << "Module C: Event signaled! Processing..." << std::endl;
            Sleep(500);  // Simulate processing
            
            // Module C knows it's a manual reset event but does not reset it
            // relying on another module to do so (potentially a design issue)
            std::cout << "Module C: Relying on another module to reset the event" << std::endl;
            
            std::cout << "Module C: Processing complete" << std::endl;
        }
        
        return 0;
    }
};

int main() {
    std::cout << "Example 4: Unified Event Creation Mode\n" << std::endl;
    
    // Create threads for each module
    std::vector<HANDLE> threads;
    
    HANDLE hThreadA = CreateThread(NULL, 0, ModuleA::ThreadFunc, NULL, 0, NULL);
    if (hThreadA != NULL) threads.push_back(hThreadA);
    
    HANDLE hThreadB = CreateThread(NULL, 0, ModuleB::ThreadFunc, NULL, 0, NULL);
    if (hThreadB != NULL) threads.push_back(hThreadB);
    
    HANDLE hThreadC = CreateThread(NULL, 0, ModuleC::ThreadFunc, NULL, 0, NULL);
    if (hThreadC != NULL) threads.push_back(hThreadC);
    
    // Wait for threads to start and begin waiting
    Sleep(1000);
    
    // Signal the event through Module A's interface
    std::cout << "\nMain thread: Getting event through Module A and signaling it..." << std::endl;
    HANDLE hEvent = ModuleA::GetSystemStatusEvent();
    SetEvent(hEvent);
    
    // Wait for all threads to finish processing
    std::cout << "Main thread: Waiting for all modules to process the event..." << std::endl;
    WaitForMultipleObjects(static_cast<DWORD>(threads.size()), &threads[0], TRUE, INFINITE);
    
    std::cout << "\nMain: Demo completed. Observations:" << std::endl;
    std::cout << "  1. EventService ensures a consistent reset mode across modules" << std::endl;
    std::cout << "  2. Warnings are issued when a module requests an inconsistent mode" << std::endl;
    std::cout << "  3. All modules can receive the event notification" << std::endl;
    std::cout << "  4. Clear ownership of event resetting is established" << std::endl;
    
    // Clean up
    for (size_t i = 0; i < threads.size(); i++) {
        CloseHandle(threads[i]);
    }
    
    // EventService destructor will close the event handle
    delete EventService::GetInstance();
    
    std::cout << "\nPress Enter to exit..." << std::endl;
    std::cin.get();
    
    return 0;
}
